package cn.good.yan.service.t6;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * 6. CAS
 * 多线程下的 原子操作 - 验证ABA问题
 *
 * @author shengren.yan
 * @create 2024-03-30
 */
public class CASDemo5 {

    // 【多线程下的 原子操作 - 验证ABA问题】 原子类
    static AtomicInteger atomicInteger = new AtomicInteger(100);
    // 原子类 - 带版本号的
    static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {
        new Thread(() -> {
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t" + "【t1线程】首次版本号：" + stamp);
            // 暂停500毫秒,保证后面的t4线程初始化拿到的版本号和我一样
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 初始值是 100，改为 101，版本号也对应 +1操作
            stampedReference.compareAndSet(100, 101, stampedReference.getStamp(), stampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t 100 改为101  " + "2次流水号：" + stampedReference.getStamp());
            // 初始值是 101，改为 100，版本号也对应 +1操作 【相当于 值被改为初始值，但版本号变化了】
            stampedReference.compareAndSet(101, 100, stampedReference.getStamp(), stampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t 101 改为100 " + "3次流水号：" + stampedReference.getStamp());
        }, "t1").start();

        new Thread(() -> {
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t" + "【t2线程】首次版本号：" + stamp);
            // 暂停1秒钟线程,等待上面的t3线程，发生了ABA问题 -- 模拟延迟
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 初始值是 100，改为 200，版本号也对应 +1操作
            boolean b = stampedReference.compareAndSet(100, 200, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName() + "\t 100 改为200 更改状态：" + b + " - 最新值和版本号" + stampedReference.getReference() + "\t" + stampedReference.getStamp());
        }, "t2").start();
    }

    private static void abaHappen() {
        new Thread(() -> {
            atomicInteger.compareAndSet(100, 101);
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicInteger.compareAndSet(101, 100);
        }, "t1").start();

        new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicInteger.compareAndSet(100, 2022) + "\t" + atomicInteger.get());
        }, "t2").start();
    }

}
